﻿using System;
using System.Collections.Generic;
using System.Text;
using Vortex.Drawing;

namespace Vortex.SceneFramework.Gui {
	/// <summary>
	/// Simple and flexible slider GUI control. Can be oriented horizontally and vertically (depends on width/height aspect ratio).
	/// </summary>
	public class Slider : RangeWidget {

		#region Drawing Slider

		/// <summary>
		/// Draws the slider element based on styles
		/// </summary>
		/// <param name="canvas">The canvas to use for slider drawing.</param>
		protected override void Draw(Canvas2D canvas) {
			//first, draw background (it extends for all widget size)			
			DrawBackground(canvas, BoundingBox);

			//second one, determine a position of slider drag control
			SliderParams sliderParams;
			if (GetSliderParams(out sliderParams)) {
				float size = sliderParams.Orientation == Orientation.Horizontal ? BoundingBox.Height : BoundingBox.Width;
				float offset = (float)Math.Floor(ValueRatio * sliderParams.DragSize);
				Vector2 offsetVector = sliderParams.Orientation == Orientation.Horizontal ? new Vector2(offset, 0) : new Vector2(0, offset);
				Rect foregroundRegion = Rect.FromBox(BoundingBox.LeftTop + offsetVector, new Vector2(size));
				DrawForeground(canvas, foregroundRegion);
			}
		}

		#endregion

		#region Input Processing

		/// <summary>
		/// Processes the moving of slider to specified location by user.
		/// </summary>
		/// <param name="location">The location in slider coordinate space.</param>
		protected void ProcessMoveSliderTo(Vector2 location) {
			SliderParams sliderParams;
			if (GetSliderParams(out sliderParams)) {
				float locationRatio =
					((sliderParams.Orientation == Orientation.Horizontal ? location.X : location.Y) - sliderParams.Size * 0.5f) / sliderParams.DragSize;

				Value = (int)(Math.Round((MaxValue - MinValue) * locationRatio + MinValue));
			}
		}

		protected internal override void ProcessMouseDown(MouseEventInfo eventInfo) {
			base.ProcessMouseDown(eventInfo);

			//move slider if left mouse down occurred
			if (eventInfo.Button == Vortex.Input.MouseButton.Left) {
				ProcessMoveSliderTo(eventInfo.Location);
			}
		}

		/// <summary>
		/// Processes the mouse move over the slider.
		/// </summary>
		/// <param name="eventInfo">The event info.</param>
		protected internal override void ProcessMouseMove(MouseEventInfo eventInfo) {
			//determination of slider parameter on mouse move with left pressed button
			if (eventInfo.IsLeftButtonDown) {
				ProcessMoveSliderTo(eventInfo.Location);
			}

			base.ProcessMouseMove(eventInfo);
		}

		#endregion

		#region Slider Params

		/// <summary>
		/// Gets the slider params.
		/// </summary>
		/// <param name="sliderParams">The resulted slider params.</param>
		/// <returns><c>true</c> if slider size is valid, otherwise <c>false</c></returns>
		protected bool GetSliderParams(out SliderParams sliderParams) {
			Vector2 size = Size;
			if (!size.IsEmpty && size.X != size.Y) {
				sliderParams = new SliderParams(size);
				return true;
			} else {
				sliderParams = default(SliderParams);
				return false;
			}
		}

		///<summary>Slider size & orientation parameters</summary>
		protected struct SliderParams {
			private Orientation _orientation;
			private float _size;
			private float _dragSize;

			/// <summary>
			/// Gets the orientation of slider.
			/// </summary>
			/// <value>The orientation of slider.</value>
			public Orientation Orientation { 
				get { return _orientation;}
			}

			/// <summary>
			/// Gets the size of the drag space.
			/// </summary>
			/// <value>The size of the drag.</value>
			public float DragSize {
				get { return _dragSize; }
			}

			/// <summary>
			/// Gets the size of slider foreground.
			/// </summary>
			/// <value>The size of slider foreground.</value>
			public float Size {
				get { return _size; }
			}

			/// <summary>
			/// Initializes a new instance of the <see cref="SliderParams"/> struct.
			/// </summary>
			/// <param name="slideControlSize">Size of the slide control.</param>
			public SliderParams(Vector2 slideControlSize) {
				if (slideControlSize.X > slideControlSize.Y) {
					_orientation = Orientation.Horizontal;
					_dragSize = slideControlSize.X - slideControlSize.Y;
					_size = slideControlSize.Y;
				} else {
					_orientation = Orientation.Vertical;
					_dragSize = slideControlSize.Y - slideControlSize.X;
					_size = slideControlSize.X;
				}
			}
		}

		#endregion
	}
}
